﻿namespace SpamChecker

open System
open TokenProbability
open TokenReader

// Checks emails in given files for spam posibilities
module SpamChecker =
    // We are interested only in first 15 tokens
    [<Literal>]
    let private relevantTokenCount = 15
    
    // Helper function for multiplying all data in sequence
    let rec private MultiplyAllElements list =
        match list with
        | head :: tail -> head * MultiplyAllElements tail
        | [] -> 1m

    // Probability table
    let private P = TokenProbability.GetProbabilityTable()

    // Returns probability for all given tokens
    let private GetTokenProbabilities(tokens) = 
        seq { 
            for token in tokens do
                yield if P.ContainsKey(token) then P.[token] else 0.4m
        }

    // Returns most relevant found probabilities of given tokens
    let private GetMostRelevantProbabilities(tokens) =
        GetTokenProbabilities(tokens) 
            |> Seq.map(fun(p) -> p, Math.Abs(0.5m - p))
            |> Seq.sortBy(fun(p, relevance) -> (~-)relevance)
            |> Seq.take(relevantTokenCount)
            |> Seq.map(fun(p, relevance) -> p)
            
    // Computes probability for email based on given tokens
    let private GetMailProbabily(tokens) = 
        let pList = GetMostRelevantProbabilities(tokens) |> Seq.toList
        let m1 = MultiplyAllElements(pList)
        let m2 = MultiplyAllElements(pList |> Seq.map(fun(p) -> 1m - p) |> Seq.toList)
        m1 / (m1 + m2)
        
    // Checks all emails in CSV in given path for spam posibility
    // Returns concatenated mail tokens (for human checking purposes) and probability of email being spam
    let CheckMailsInCsv(path) = 
        let tokensPerMail = TokenReader.GetWordDensityMapPerRow(path)
        seq<string * decimal> {
            for mailTokens in tokensPerMail do
                yield String.Join(" ", mailTokens.Keys), GetMailProbabily(mailTokens |> Seq.map(fun(KeyValue(token, count)) -> token))
        }
